﻿using Newtonsoft.Json;
using S7.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace JNPF.Service
{
    public class PLCService
    {
        Plc PLC;
        Thread thReadData = null;
        private static PLCService instance = null;
        private static bool isStart = false;

        public static PLCService GetIntance()
        {
            if (instance == null)
            {
                instance = new PLCService();
            }
            return instance;
        }
        private PLCService()
        {
            PLC = new Plc(CpuType.S71200, "192.168.123.211", 0, 1);
        }

        public void StartPlcService()
        {
            if (!isStart)
            {
                isStart = ServiceStart();
            }
        }

        public bool ServiceStart()
        {
            if (ConnectPLC())
            {
                InitThread(thReadData);
                thReadData = new Thread(ReadPLCData);
                thReadData.IsBackground = true;
                thReadData.Start();
                return true;
            }
            else
            {
                return false;
            }
        }
        
        private void ReadPLCData()
        {
            while (true)
            {
                if (ConnectPLC())
                {
                    //todo 读取plc
                    /*
                     * 1. 获取点位列表 与 类型
                     * 2. 读取数据
                     * 3. 解析数据
                     * 4. 保存数据到消息队列
                     */

                    //2.读取plc
                    ReadPLC();
                }

                Thread.Sleep(500);
            }
        }
        private bool ConnectPLC()
        {
            if (!PLC.IsConnected)
            {
                try
                {
                    PLC.Open();
                }
                catch (Exception ex)
                {
                    //todo 添加plc连接日志
                    return false;
                }
            }
            return PLC.IsConnected;
        }
        private string ReadPLC()
        {
            //PLC.Read()
            return string.Empty;
        }
        
        private string ToBoolStr(int? isChecked)
        {
            if (isChecked == 1) return "true";

            else
            {
                return "false";
            }
        }
        /// <summary>
        /// 去指定字符串中间字符
        /// </summary>
        /// <param name="sourse">字符串</param>
        /// <param name="startstr">首字符</param>
        /// <param name="endstr">尾字符</param>
        /// <returns></returns>
        public static string MidStrEx(string sourse, string startstr, string endstr)
        {
            string result = string.Empty;
            int startindex, endindex;
            try
            {
                startindex = sourse.IndexOf(startstr);
                if (startindex == -1)
                {
                    return result;
                }
                string tmpstr = sourse.Substring(startindex + startstr.Length);
                endindex = tmpstr.IndexOf(endstr);
                if (endindex == -1)
                {
                    return result;
                }
                result = tmpstr.Remove(endindex);

            }
            catch (Exception)
            {

            }
            return result;
        }
        /// <summary>
        /// 写入PLC数值
        /// </summary>
        /// <param name="DataTag"></param>
        public void WritePLC(string DataTag, string Data)
        {
            try
            {
                #region 逻辑处理

                string Type = "STRING";
                if (DataTag.Contains("S"))
                {
                    Type = "STRING";
                }
                else if (DataTag.Contains("DBW"))
                {
                    Type = "Word";
                }
                else if (DataTag.Contains("DBB"))
                {
                    Type = "Byte";
                }
                else if (DataTag.Contains("DBD"))
                {
                    Type = "Dint";
                }
                else if (DataTag.Contains("DBI"))
                {
                    Type = "int";
                }
                else if (DataTag.Contains("DBX"))
                {
                    Type = "Bool";
                }
                else if (DataTag.Contains("DBR"))
                {
                    Type = "Real";
                }


                int strAdr = 0;
                //取到db块号
                int dbInt = dbInt = int.Parse(MidStrEx(DataTag, "DB", ".")); ;
                //字符串类型
                if (Type == "STRING")
                {
                    //取到地址
                    //  strAdr = int.Parse(MidStrEx(DataTag, "STRING", "."));
                    strAdr = int.Parse(Regex.Match(DataTag, @"\d+$").ToString());
                    //写入PLC数据
                    PLC.Write(DataType.DataBlock, dbInt, strAdr, GetPLCStringByteArray(Data));
                }
                else if (Type == "Word")
                {
                    //写入整数型
                    strAdr = int.Parse(Regex.Match(DataTag, @"\d+$").ToString());
                    PLC.Write(DataType.DataBlock, dbInt, strAdr, Convert.ToInt16(Data));
                }
                else if (Type == "Byte")
                {
                    //写入字节型
                    strAdr = int.Parse(Regex.Match(DataTag, @"\d+$").ToString());
                    PLC.Write(DataType.DataBlock, dbInt, strAdr, Convert.ToByte(Data));
                }
                else if (Type == "Real")
                {
                    //写入实数
                    strAdr = int.Parse(Regex.Match(DataTag, @"\d+$").ToString());
                    PLC.Write(DataType.DataBlock, dbInt, strAdr, (float)Convert.ToDouble(Data));

                }
                else if (Type == "Bool")
                {
                    //写入Bool值
                    PLC.Write(DataTag.ToUpper(), Convert.ToBoolean(Data));
                }
                else if (Type == "Dint")
                {
                    //写入整型
                    strAdr = int.Parse(Regex.Match(DataTag, @"\d+$").ToString());
                    PLC.Write(DataType.DataBlock, dbInt, strAdr, (int)Convert.ToInt32(Data));
                }
                else if (Type == "int")
                {
                    //写入整型
                    strAdr = int.Parse(Regex.Match(DataTag, @"\d+$").ToString());
                    PLC.Write(DataType.DataBlock, dbInt, strAdr, (ushort)Convert.ToInt16(Data));
                }
                #endregion
            }
            catch (Exception ex)
            {
                //写入异常
                Console.WriteLine("写入PLC数据错误" + ex.Message);
            }
        }

        /// <summary>
        /// 获取西门子PLC字符串数组--String
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private byte[] GetPLCStringByteArray(string str)
        {
            byte[] value = Encoding.Default.GetBytes(str);
            byte[] head = new byte[2];
            head[0] = Convert.ToByte(254);
            head[1] = Convert.ToByte(str.Length);
            value = head.Concat(value).ToArray();
            return value;
        }
        /// <summary>
        /// 获取西门子PLC字符串数组--WString
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private byte[] GetPLCWStringByteArray(string str)
        {
            byte[] value = Encoding.BigEndianUnicode.GetBytes(str);
            byte[] head = BitConverter.GetBytes((short)508);
            byte[] length = BitConverter.GetBytes((short)str.Length);
            Array.Reverse(head);
            Array.Reverse(length);
            head = head.Concat(length).ToArray();
            value = head.Concat(value).ToArray();
            return value;
        }

        private void InitThread(Thread th)
        {
            if (th != null)
            {
                try
                {
                    th.Abort();
                    th = null;
                }
                catch { }
            }
        }
    }
}
